package com.tgy.MyFlowable.workflow.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 流程脚本工具类，用于脚本编写
 *
 * @version 1.0
 * @author: wang xiao xiang
 * @date: 2021/8/9 9:37
 */
@Slf4j
@Component
public class BpmScriptUtil {
    public static final String FORM_DATA_VARIABLE_KEY = "formData";

    /**
     * 给流程实例设置变量
     * @param delegateExecution 执行实例
     * @param variableName 变量名
     * @param variableValue 变量值
     */
    public static void setVariableForInstance(DelegateExecution delegateExecution,
                                              String variableName,
                                              Object variableValue) {
        RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
        log.error(">>> 给流程实例设置变量");
        if (ObjectUtil.isNotNull(delegateExecution)) {
            String processInstanceId = delegateExecution.getProcessInstanceId();
            runtimeService.setVariable(processInstanceId, variableName, variableValue);
        } else {
            log.error(">>> 设置变量异常，执行实例不存在");
        }
        log.error(">>> 给流程实例设置变量成功");
    }

    /**
     * 给任务设置变量
     * @param delegateExecution 执行实例
     * @param variableName 变量名
     * @param variableValue 变量值
     */
    public static void setVariableForTask(DelegateExecution delegateExecution,
                                          String variableName,
                                          Object variableValue) {
        RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
        TaskService taskService = SpringUtil.getBean(TaskService.class);
        if (ObjectUtil.isNotNull(delegateExecution)) {
            String executionId = delegateExecution.getId();
            Task task = taskService.createTaskQuery().executionId(executionId).singleResult();
            if (ObjectUtil.isNotNull(task)) {
                taskService.setVariable(task.getId(), variableName, variableValue);
            } else {
                log.error(">>> 设置变量异常，任务不存在");
            }
        } else {
            log.error(">>> 设置变量异常，执行实例不存在");
        }
    }

    /**
     * 获取流程表单数据，可以通过修改此接口，将获取到的表单数据保存到自己的业务表
     * @param delegateExecution 执行实例
     * @return
     */
    public static Map<String, Object> getFormData(DelegateExecution delegateExecution) {
        Map<String, Object> variables = delegateExecution.getVariables();
        AtomicReference<Map<String, Object>> formData = new AtomicReference<>();
        variables.forEach((s, o) -> {
            //名字为formData的参数，就是表单数据，因此注意只能有一个参数formData，否则前面的会被后面的覆盖
            if (FORM_DATA_VARIABLE_KEY.equals(s)) {
                JSONObject jsonObject = JSONUtil.parseObj(o);
                formData.set(jsonObject);
                //此处可以自定义处理
                log.info(">>> 任务完成时接受到的表单数据:{}", jsonObject);
            }
        });
        return formData.get();
    }

    /**
     * 获取流程表单数据的key对应的value
     * @param delegateExecution
     * @param key 表单数据key
     * @return
     */
    public static Object getFormDataKey(DelegateExecution delegateExecution, String key) {
        Map<String, Object> formData = getFormData(delegateExecution);
        if(ObjectUtil.isNotEmpty(formData)) {
            return formData.get(key);
        }
        return null;
    }

    /**
     * 利用反射调用service的方法保存表单数据
     * @param serviceName service的名称，如demoService
     * @param methodName 方法名称，如save
     * @param formData 接收的参数，必须是Map[String, Object]类型
     */
    public static void saveBusinessData(String serviceName, String methodName, Map<String, Object> formData) {
        if (ObjectUtil.isAllNotEmpty(serviceName, methodName, formData)) {
            Object serviceClass = SpringUtil.getBean(serviceName);
            if(ObjectUtil.isNull(serviceClass)) {
                log.error(">>> 利用反射调用service的方法保存表单数据错误：service不存在，请检查service是否存在或被spring管理");
            } else {
                Method method = ReflectUtil.getMethod(serviceClass.getClass(), methodName, JSONObject.class);
                if (ObjectUtil.isNull(method)) {
                    log.error(">>> 利用反射调用service的方法保存表单数据错误：方法不存在，请检查方法是否存在或方法参数是否正确");
                } else {
                    try {
                        Object invoke = ReflectUtil.invoke(serviceClass, method, formData);
                        log.info(">>> 执行保存表单数据完成，保存的参数：{}", formData);
                    } catch (Exception e) {
                        log.error(">>> 利用反射调用service的方法保存表单数据错误：保存方法执行失败，请参加日志");
                    }
                }
            }
        } else {
            log.error(">>> 利用反射调用service的方法保存表单数据错误：参数不完整");
        }
    }
}
